package com.xhai.common.utils.ip;

import com.xhai.common.constant.Constants;
import com.xhai.common.utils.classes.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author xhai
 * @description IP相关工具类
 * @date 2025/6/6
 */
public class IpUtils {

    public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
    // 匹配 ip
    public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
    // 匹配网段
    public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
    // 匹配通配符ip
    public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";

    /**
     * 校验ip是否符合过滤串规则
     *
     * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
     * @param ip     校验IP地址
     * @return
     */
    public static boolean isMatchedIp(String filter, String ip) {
        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) {
            return false;
        } else if (!isIP(ip)) {
            return false;
        }

        String[] ips = filter.split(";");
        for (String ipStr : ips) {
            if (isIP(ipStr) && ipStr.equals(ip)) {
                return true;
            } else if (isIpWildCard(ipStr) && ipIsInWildCardNoCheck(ipStr, ip)) {
                return true;
            } else if (isIPSegment(ipStr) && ipIsInNetNoCheck(ipStr, ip)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断ip是否在网段中
     *
     * @param ipNet 特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
     * @param ip
     * @return
     */
    private static boolean ipIsInNetNoCheck(String ipNet, String ip) {
        int internalIndex = ip.indexOf("-");
        String[] leftIpItems = ipNet.substring(0, internalIndex).split("\\.");
        String[] rightIpItems = ipNet.substring(internalIndex + 1).split("\\.");
        String[] ipItems = ip.split("\\.");
        long leftIpL = 0L, rightIpL = 0L, ipL = 0L;
        for (int i = 0; i < 4; ++i) {
            leftIpL = leftIpL << 8 | Integer.parseInt(leftIpItems[i]);
            rightIpL = rightIpL << 8 | Integer.parseInt(rightIpItems[i]);
            ipL = ipL << 8 | Integer.parseInt(ipItems[i]);
        }
        if (leftIpL < rightIpL) {
            long t = leftIpL;
            leftIpL = rightIpL;
            rightIpL = t;
        }

        return leftIpL >= ipL && ipL >= rightIpL;
    }

    /**
     * 判断ipSeg是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
     *
     * @param ipSeg
     * @return
     */
    private static boolean isIPSegment(String ipSeg) {
        return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
    }

    /**
     * 判断IP是否在ip通配符中
     *
     * @param ipWildCard 包含通配符的ip
     * @param ip
     * @return
     */
    private static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip) {
        String[] wildIpItems = ipWildCard.split("\\.");
        String[] ipItems = ip.split("\\.");
        for (int i = 0; i < wildIpItems.length && !wildIpItems[i].equals("*"); i++) {
            if (!wildIpItems[i].equals(ipItems[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判斷是否为通配符*为间隔的ip地址
     *
     * @param ip
     * @return
     */
    private static boolean isIpWildCard(String ip) {
        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
    }

    /**
     * 判断是否是ip
     *
     * @param ip
     * @return
     */
    public static boolean isIP(String ip) {
        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
    }

    /**
     * 获取客户端ip地址
     *
     * @return 客户端ip地址
     */
    public static String getServletIpAddr() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return Constants.IP_UNKNOWN;
        }
        return getIpAddr(attributes.getRequest());
    }

    /**
     * 根据请求获取ip地址
     *
     * @param request 请求对象
     * @return 请求所在ip地址
     */
    private static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return Constants.IP_UNKNOWN;
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || StringUtils.isEmpty(ip) || StringUtils.equalsIgnoreCase(Constants.IP_UNKNOWN, ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || StringUtils.isEmpty(ip) || StringUtils.equalsIgnoreCase(Constants.IP_UNKNOWN, ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || StringUtils.isEmpty(ip) || StringUtils.equalsIgnoreCase(Constants.IP_UNKNOWN, ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || StringUtils.isEmpty(ip) || StringUtils.equalsIgnoreCase(Constants.IP_UNKNOWN, ip)) {
            ip = request.getHeader("X-Real-IP");
        }

        if (ip == null || StringUtils.isEmpty(ip) || StringUtils.equalsIgnoreCase(Constants.IP_UNKNOWN, ip)) {
            ip = request.getRemoteAddr();
        }

        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
    }

    /**
     * 从多级反向代理中获得第一个非unknown IP地址
     *
     * @param ip 获得的IP地址
     * @return 第一个非unknown IP地址
     */
    private static String getMultistageReverseProxyIp(String ip) {
        // 多级反向代理检测
        if (ip != null && ip.indexOf(",") > 0) {
            final String[] ips = ip.trim().split(",");
            for (String subIp : ips) {
                if (StringUtils.equalsIgnoreCase(Constants.IP_UNKNOWN, ip)) {
                    ip = subIp;
                    break;
                }
            }
        }
        return StringUtils.substring(ip, 0, 255);
    }
}
